package com.xh.easyretry.strategy.retry;

import com.alibaba.fastjson.JSON;
import com.xh.easyretry.common.XHRetryContext;
import com.xh.easyretry.common.result.BaseResult;
import com.xh.easyretry.common.result.CommonResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.Executor;

import static com.xh.easyretry.common.XHRetryConstants.ASYNC_STRATEGY;


@Slf4j
@Component
public class AsyncRetryStrategy extends AbstractRetryStrategy {

    @Autowired
    private Executor retryTaskExecutor;

    @Override
    public String getStrategy() {
        return ASYNC_STRATEGY;
    }

    @Override
    public Object execRetry(XHRetryContext retryContext) {
        if (Objects.isNull(retryContext)) {
            return null;
        }
        retryTaskExecutor.execute(() -> {
            while (canExecRetry(retryContext)) {
                final Integer currentRetryCount = retryContext.getCurrentRetryCount();
                Method method = retryContext.getMethod();
                try {
                    log.info("act=AsyncRetryStrategy.execRetry msg=当前重试次数={} 开始重试", currentRetryCount);
                    Object result = method.invoke(retryContext.getBean(), retryContext.getArgs());
                    log.info("act=AsyncRetryStrategy.execRetry msg=当前重试次数={} 完成重试 result={}",
                            currentRetryCount, JSON.toJSONString(result));
                    if (Objects.isNull(result)) {
                        return;
                    } else if (result instanceof BaseResult) {
                        if (((BaseResult) result).isSuccess()) {
                            return;
                        }
                        if (!Objects.equals(((BaseResult) result).getCode(), CommonResultCode.NEED_RETRY_FAIL)) {
                            return;
                        }
                    }
                    log.info("act=AsyncRetryStrategy.execRetry msg=当前重试次数={} 重试仍然失败", currentRetryCount);
                    retryFailed(retryContext, null);
                } catch (Exception e) {
                    log.error("act=AsyncRetryStrategy.execRetry msg=当前重试次数={} 重试时抛出异常", currentRetryCount, e);
                    retryFailed(retryContext, null);
                }
            }
        });
        return buildResult(retryContext);
    }
}
